<!DOCTYPE html>
<html>
  <head>
    <script src="../../../resources/testharness.js"></script>
    <script src="../../../resources/testharnessreport.js"></script>
    <style>
      div {
        font-family: Arial;
        font-size: 16px;
        font-weight: normal;
        font-style: normal;
        text-rendering: optimizeLegibility;
        font-kerning: none;
        font-variant-ligatures: none;
      }

      .rect-outline {
        position: absolute;
        outline: 5px solid rgba(255, 0, 0, .75);
        z-index: -1;
      }
     
      .box {
        display: inline-block;
        width: 400px;
        line-height: 40px;
        margin: 0 40px 40px 0;
      }
      
      .box.expected {
        white-space: nowrap;
      }
     
      .caption {
          border-bottom: 1px solid black;
          font-weight: bold;
      }
     
      .outer {
        display: block;
        outline: 2px solid green;
      }
     
      .inner {
        display: inline-block;
        width: 40px;
        height: 20px;
        outline: 2px solid blue;
      }
     
      #test8, #test8-expected {
        transform: translate(50px, 100px) rotate(50deg);
      }
     
      #test9, #test9-expected {
        height: 400px;
        -webkit-writing-mode: vertical-lr;
      }

      #testArea {
        width: 900px;
      }
    </style>
  </head>
  <body>
    <div id="testArea">
      <div class="box caption">Actual</div>
      <div class="box caption">Expected</div>
      <div class="box" id="test1">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test1-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor incididunt ut labore et dolore</span><br>
        <span>magna aliqua. Ut enim ad minim veniam, quis nostrud</span><br>
        <span>exercitation ullamco laboris nisi ut aliquip ex ea</span><br>
        <span>commodo consequat.</span>
      </div>

      <div class="box" id="test2">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test2-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor incididunt ut labore et dolore</span><br>
        <span>magna aliqua. Ut enim ad minim veniam, quis nostrud</span><br>
        <span>exercitation ullamco laboris nisi ut aliquip ex ea</span><br>
        <span>commodo consequat.</span>
      </div>

      <div class="box" id="test3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test3-expected">
        Lorem ipsu<span>m dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor incididunt ut labore et dolore</span><br>
        <span>magna aliqua. Ut enim ad minim veniam, quis nostrud</span><br>
        <span>exercitation ullamco laboris nisi ut </span>aliquip ex ea<br>
        commodo consequat.
      </div>
      
      <div class="box" id="test4">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor<img src="../resources/abe.png" width="76" height="103"> incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test4-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor</span><img src="../resources/abe.png" width="76" height="103"><span> incididunt ut labore et</span><br>
        <span>dolore magna aliqua. Ut enim ad minim veniam, quis</span><br>
        <span>nostrud exercitation ullamco laboris nisi ut aliquip ex ea</span><br>
        <span>commodo consequat.</span> 
      </div>
      
      <div class="box" id="test5">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor<img src="../resources/abe.png" width="76" height="103"> incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test5-expected">
        Lorem ipsu<span>m dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor</span><img src="../resources/abe.png" width="76" height="103"><span> incididunt ut labore et</span><br>
        <span>dolore magna aliqua. Ut e</span>nim ad minim veniam, quis<br>
        nostrud exercitation ullamco laboris nisi ut aliquip ex ea<br>
        commodo consequat.
      </div>
      
      <div class="box" id="test6">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do <div class="outer">eiusmod <div class="inner"></div>tempor</div> incididunt ut labore etdolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test6-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do</span><br>
        <div class="outer"><span>eiusmod </span><div class="inner"></div><span>tempor</span></div>
        <span>incididunt ut labore etdolore magna aliqua. Ut enim ad</span><br>
        <span>minim veniam, quis nostrud exercitation ullamco laboris</span><br>
        <span>nisi ut aliquip ex ea commodo consequat.</span>
      </div>
      
      <div class="box" id="test7">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do <div class="outer">eiusmod <div class="inner"></div>tempor</div> incididunt ut labore etdolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test7-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do</span><br>
        <span class="outer"><span>eiusmod </span><div class="inner"></div><span>tempor</span></span>
        <span>incididunt ut labore etdolore magna aliqua. Ut enim ad</span><br>
        <span>minim veniam, quis nostrud exercitation ullamco laboris</span><br>
        <span>nisi ut aliquip ex ea commodo consequat.</span>
      </div>
      
      <div class="box" id="test8">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test8-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor incididunt ut labore et dolore</span><br>
        <span>magna aliqua. Ut enim ad minim veniam, quis nostrud</span><br>
        <span>exercitation ullamco laboris nisi ut aliquip ex ea</span><br>
        <span>commodo consequat.</span>
      </div>
      
      <div class="box" id="test9">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
      <div class="box expected" id="test9-expected">
        <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span><br>
        <span>sed do eiusmod tempor incididunt ut labore et dolore</span><br>
        <span>magna aliqua. Ut enim ad minim veniam, quis nostrud</span><br>
        <span>exercitation ullamco laboris nisi ut aliquip ex ea</span><br>
        <span>commodo consequat.</span>
      </div>
    </div>

    <script>
      function addRectOutline(rect)
      {
          var scrollTop = document.scrollingElement.scrollTop;
          var element = document.createElement('div');;
          element.className = 'rect-outline';
          element.style.left = rect.left + 'px';
          element.style.top = (rect.top + scrollTop) + 'px';
          element.style.width = (rect.right - rect.left) + 'px';
          element.style.height = (rect.bottom - rect.top) + 'px';
          document.body.appendChild(element);
      }
  
      function showRects(rects)
      {
        for (var rect, i = 0; rect = rects[i]; i++)
          addRectOutline(rect);
      }
  
      function rectsForRange(range) {
        var clientRects = range.getClientRects();
        var rects = [];
        for (var i = 0; i < clientRects.length; i++)
          rects.push(clientRects[i]);
        return rects;
      }
  
      function rectsForChildren(element, opt_tagName) {
        var elements = element.getElementsByTagName(opt_tagName || 'span');
        var rects = [];
        for (var el, i = 0; el = elements[i]; i++) {
          if (el.tagName != 'BR')
            rects.push(el.getBoundingClientRect());
        }
        return rects;
      }
  
      function adjustedRectPosition(container, rect) {
          var containerRect = container.getBoundingClientRect();
          return (rect.left - containerRect.left).toFixed(0) + ',' +
            (rect.top - containerRect.top).toFixed(0);
      }
  
      function rectSize(rect) {
        return rect.width.toFixed(0) + 'x' + rect.height.toFixed(0);
      }
  
  
      if (window.testRunner)
          testRunner.setTextSubpixelPositioning(true);
  
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test1');
        range.selectNode(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test1-expected');
        var expectedRects = [
          expectedElement.getBoundingClientRect()
        ].concat(rectsForChildren(expectedElement));
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.selectNode(container) has rects for container and each line.');
  
  
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test2');
        range.selectNodeContents(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test2-expected');
        var expectedRects = rectsForChildren(expectedElement);
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.selectNodeContents(container) has rects for each line.');
  
  
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test3');
        range.setStart(actualElement.firstChild, 10);
        range.setEnd(actualElement.lastChild, 200);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test3-expected');
        var expectedRects = rectsForChildren(expectedElement);
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.setStart/setEnd(node, offset) has rects for each line in range.');
  
  
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test4');
        range.selectNode(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test4-expected');
        var expectedRects = [
          expectedElement.getBoundingClientRect()
        ].concat(rectsForChildren(expectedElement));
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.selectNode(container) should not include rect of image.');
      
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test5');
        range.setStart(actualElement.firstChild, 10);
        range.setEnd(actualElement.lastChild, 50);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test5-expected');
        var expectedRects = rectsForChildren(expectedElement, '*');
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.setStart/setEnd(node, offset) should include rect of image.');
      
      
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test6');
        range.selectNode(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test6-expected');
        var expectedRects = [
          expectedElement.getBoundingClientRect()
        ].concat(rectsForChildren(expectedElement));
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.selectNode(container) should not include green/blue boxes.');
      
      
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test7');
        range.selectNodeContents(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test7-expected');
        var expectedRects = rectsForChildren(expectedElement);
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'range.selectNodeContents() should select green but not blue box.');
  
  
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test8');
        range.selectNodeContents(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test8-expected');
        var expectedRects = rectsForChildren(expectedElement);
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'transform, range.selectNodeContents() has rects for each line.');
      
      
      test(function() {
        var range = document.createRange();
        var actualElement = document.getElementById('test9');
        range.selectNodeContents(actualElement);
        var actualRects = rectsForRange(range);
  
        var expectedElement = document.getElementById('test9-expected');
        var expectedRects = rectsForChildren(expectedElement);
  
        if (!window.testRunner) {
          showRects(actualRects);
          showRects(expectedRects);
        }
  
        assert_equals(actualRects.length, expectedRects.length,
          'Number of rects returned by getClientRects should match expected.');
  
        for (var i = 0; i < actualRects.length; i++) {
          var actual = actualRects[i];
          var expected = expectedRects[i];
          assert_equals(adjustedRectPosition(actualElement, actual),
                        adjustedRectPosition(expectedElement, expected),
                        'Position of rect ' + i + ' should match expected.');
          assert_equals(rectSize(actual),
                        rectSize(expected),
                        'Size of rect ' + i + ' should match expected');
        }
      }, 'vertical, range.selectNodeContents() has rects for each line.');
    </script>
  </body>
</html>
